import classNames from 'classnames';
import { type FC, useMemo, Fragment } from 'react';
import { useMemoizedFn, useSafeState } from 'ahooks';
import { useListenMessage } from '@/components/Socket/hooks';
import type { ChatHistoryType, SubHistory } from './types';
import Loading from '@/components/Loading';

import ChatLogo from '../Logo';
import TextNode from './text';
import { useMessages } from './hooks';

import styles from './styles.module.less';

type ChatHistoryProps = Omit<ChatHistoryType, 'messages'> & {
  onPrinit?: () => void;
  defaultMessages?: SubHistory[];
  onDone?: (history: ChatHistoryType) => void;
}

const ChatHistory: FC<ChatHistoryProps> = (props) => {
  const {
    isDone,
    isMe = false,
    defaultMessages = [],
  } = props;

  const {
    insertText,
    messages,
    prinitNext,
    taskCompelete
  } = useMessages(defaultMessages);

  const disabled = Boolean(isDone || isMe);
  const [loading, setLoading] = useSafeState(true);

  // 完成任务
  const onTaskDone = useMemoizedFn(() => {
    props.onDone?.({ messages, isDone: true, id: props.id });
  });

  // socket推送数据结束
  const onListenClose = useMemoizedFn(() => {
    setLoading(false);
    removeListener();
    taskCompelete();
    onTaskDone();
  });

  // 监听socket
  const [removeListener] = useListenMessage((result) => {
    if (result.task_done) {
      onListenClose();
    } else {
      const text = result.text_delta;
      if (text !== undefined) insertText(text);
    }
  }, { disabled });

  const loadingEl = useMemo(() => {
    if (!loading || disabled) {
      return null;
    }
    return <Loading />;
  }, [loading, disabled]);

  const renderMessage = (item: SubHistory, i: number) => {
    const total = messages.length;
    const lastNode = i === total - 1;
    let { visible = true, prinit } = item;
    if (props.isDone) prinit = false;

    return (
      <Fragment key={item.id}>
        {visible ? (
          <TextNode
            {...item}
            nodeIndex={i}
            prinit={prinit}
            lastNode={lastNode}
            enableMarkdown={!isMe}
            onPrintEnd={prinitNext}
            onPrinit={props.onPrinit}
          />
        ) : null}
      </Fragment>
    );
  }

  return (
    <div className={classNames(styles.chat_history, isMe && styles.me)}>
      {!isMe ? <ChatLogo size={36} /> : null}
      <div className={styles.chat_message}>
        <div className={styles.message}>
          {messages.map(renderMessage)}
          {!messages.length ? loadingEl : null}
        </div>
      </div>
    </div>
  );
}

export default ChatHistory;